#include "NetSystem.h"
#include <iostream>
#include <cstring>
using namespace std;

/****************************************************************************
 * CNetSystem()
 * Constructor de la clase CNetSystem
 * Inicia la libería SDL_net 
 ***************************************************************************/
CNetSystem::CNetSystem() {
	SDLNet_Init();
	socket = NULL;
}

/****************************************************************************
 * ~CNetSystem() => Destructor de la clase CNetSystem
 * Libera la librería SDL_net
 * Si tenemos un socket abierto, lo cierra
 ***************************************************************************/
CNetSystem::~CNetSystem() {
	if (socket) SDLNet_TCP_Close(socket);
	SDLNet_Quit();
}

/****************************************************************************
 * bind() => Permite asociar el socket a un puerto de la máquina
 * Recibe como parámetro el puerto en el que el servidor escuchará las peticiones 
 * Devuelve true si el servidor consigue el puerto 
 ***************************************************************************/
bool CNetSystem::bind(Uint16 port) {
	if (SDLNet_ResolveHost(&ip, NULL, port) == -1) return false;
	socket = SDLNet_TCP_Open(&ip);

	if (!socket) {
		cerr << "Error al abrir el puerto " << port << endl;
		return false;
	}
	return true;
}

/****************************************************************************
 * accept() => Método para el servidor, captura una conexión de un cliente
 * Devuelve un socket que comunica al servidor con el cliente
 * Si no hay conexiones devuelve NULL, el servidor no se bloquea
 ***************************************************************************/
TCPsocket CNetSystem::accept() {
	return SDLNet_TCP_Accept(socket);	
}

/****************************************************************************
 * connect() => Método para el cliente, abre una conexión con el servidor
 * Recibe el nombre del servidor y el puerto en el que está escuchando
 * Devuelve true si se establece la conexión correctamente
 ***************************************************************************/
bool CNetSystem::connect(const char * host, Uint16 port) {
	if (SDLNet_ResolveHost(&ip, host, port) == -1) return false;
	socket = SDLNet_TCP_Open(&ip);

	if (!socket) {
		cerr << "Error al abrir conexión con " << host << " en el puerto " << port << endl;
		return false;
	}
	return true;
}

/****************************************************************************
 * send() => Método usado por cliente y servidor para enviar datos
 * Recibe como parámetro una cadena con el mensaje a enviar
 * Devuelve el número de bytes enviados correctamente
 ***************************************************************************/
int CNetSystem::send(const char * msg) {
	int len = strlen(msg) + 1;

	return SDLNet_TCP_Send(socket, (void *)msg ,len);
}

/****************************************************************************
 * Permite a un servidor multihilo indicar el socket por el que enviar un mensaje
 ***************************************************************************/
int CNetSystem::send(TCPsocket sock, const char * msg) {
	int len = strlen(msg) + 1;

	return SDLNet_TCP_Send(sock, (void *)msg ,len);
}

/****************************************************************************
 * receive() => Método usado por cliente y servidor para recibir datos
 * Toma como parámetros un buffer en el que alojar el mensaje recibido
 * y un entero (maxlen) que indica la cantidad de bytes que queremos recibir
 * Devuelve el número de bytes recibidos correctamente
 ***************************************************************************/
int CNetSystem::receive(char buffer[], int maxlen) {
	return SDLNet_TCP_Recv(socket, buffer, maxlen);
}

/****************************************************************************
 * Permite a un servidor multihilo indicar el socket por el que recibir el mensaje
 ***************************************************************************/
int CNetSystem::receive(TCPsocket sock, char buffer[], int maxlen) {
	return SDLNet_TCP_Recv(sock, buffer, maxlen);
}

/****************************************************************************
 * close() => Permite cerrar un socket
 ***************************************************************************/
void CNetSystem::close() {
	SDLNet_TCP_Close(socket);
}

/****************************************************************************
 * Permite cerrar una conexión especificando el socket
 ***************************************************************************/
void CNetSystem::close(TCPsocket sock) {
	SDLNet_TCP_Close(sock);
}
